/*
————————————————————————————————————————————————————————————————————————————————————
｜ 本文件用于实现编译和运行统一的部分
｜ 设计思路：
｜ 1. 根据编译的结果判断是否运行
｜ 2. 编译错误 -> 不运行，将编译错误信息返回给上层
｜ 3. 编译成功 -> 运行
｜ 4. 判断运行是否有异常、stderr文件有内容、返回异常信息；无内容、返回stdout结果信息
————————————————————————————————————————————————————————————————————————————————————
*/

#pragma once

#include <iostream>
#include <string>

#include "runner.hpp"
#include "compiler.hpp"
#include "../Comm/Log.hpp"
#include "../Comm/Comm.hpp"
#include "Parse.hpp"

namespace ns_complie_run
{
    class Comp_Run
    {
    public:
        Comp_Run() {}
        ~Comp_Run() {}

    // 用于实现编译运行，并返回处理结果
        static void Start(const std::string &res_json, std::string &resp_json)
        {
            int status, cpu, as;
            std::string file;
        // 一. 对请求正文进行解析

            ns_parse::In_Put input(res_json);
            if (!input.Parse()) // 解析失败
            {
                status = System_Call_Err;
                goto END;
            }
            if (input.Getcode().size() == 0) // 提交的代码为空
            {
                status = CodeEmpty;
                goto END;
            }

        // 二. 形成src文件，将代码加载进去，并获得一个文件名

            if (!input.MakeSrc(file)) // code提交到文件失败
            {
                status = System_Call_Err;
                goto END;
            }

        // 三. 拿到CPU和地址空间的限制

            cpu = input.GetCPU();
            as = input.GetAS();

        // 四. 编译并运行

            status = ns_complie::Compiler::Compile(file);
            // （1）编译失败，拿到compile.err的内容 （2）系统调用失败，服务器内部错误
            if (status == Compile_Err || status == System_Call_Err)
            {
                goto END;
            }
            // （3）编译成功

            // 2. 运行 -> 拿到退出信号
            status = ns_run::Runner::Run(file, cpu, as);
            // （1）运行成功，拿run.stdout的内容
            // （2）运行时，系统调用失败，服务器内部错误
            // （3）运行失败，出现了异常信号

            END:
                // 将状态码转换为对应的状态信息
                Status_To_Message(status, file, resp_json);
                // 序列化
                resp_json = FileOper::File::Serialize(status, resp_json);
                //至此所有返回信息就已经存放在response_message里了，所以产生的临时文件也就不需要了
                //删除temp目录下的所有临时文件
                FileOper::File::DeleteTemp(file);
        }

        static void Status_To_Message(int status, std::string file, std::string &message)
        {
            switch (status)
            {
            // 系统调用错误 -》 内部错误
            case System_Call_Err: 
                message = "未知错误";
            break;
            // 编译错误
            case Compile_Err: 
            {
                FileOper::File::GetfileMessage(FileOper::File::Complie_Err(file), message);
                message = "编译错误\n" + message;
            }
            break;
            // 代码提交为空
            case CodeEmpty: 
                message = "提交的代码为空";
            break;
            // 运行成功
            case Success: 
            {
                FileOper::File::GetfileMessage(FileOper::File::StdOut(file), message);
            }
            break;
            // 触发异常
            default: 
            {
                // 这里很特殊，因为有的异常的错误信息，一部分是OS发的，一部分是程序内部抛异常发的
                // 所以就会导致有的信息可以重定向到stderr文件，有的就不可以
                FileOper::File::GetfileMessage(FileOper::File::StdErr(file), message);
                message = "运行异常退出\n" + ns_sign_to_message::signal_error_map[status];
            }
            break;
            }
        }
    };
};
